#include <iostream>

#include "mysocket.h"
#include "acceptConn.h"
#include "communication.h"

//上锁，用于线程同步，防止连接客户端线程和通信线程对主线程的readfds操作混乱
std::mutex mtx;

int main(void)
{

    //创建监听的套接字socket
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket---------------------");
        return 1;
    }

    //绑定IP和端口
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    saddr.sin_addr.s_addr = INADDR_ANY;
    int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
    if(ret == -1)
    {
        perror("bind---------------------");
        return 1;
    }

    //监听
    ret = listen(lfd, 128);
    if(ret == -1)
    {
        perror("listen---------------------");
        return 1;
    }
    std::cout << "wait for client connect..." << std::endl;

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(lfd, &readfds);

    int maxfd = lfd;
    std::cout << "maxfd = " << maxfd << std::endl;
    while(1)
    {

        mtx.lock();
        fd_set readfds_bak = readfds; //备份
        mtx.unlock();

        std::cout << "select wait..." << std::endl;
        int ret = select(maxfd+1, &readfds_bak, NULL, NULL, NULL);
        if(ret == -1)
        {
            perror("select");
            return 1;
        }

        if(FD_ISSET(lfd, &readfds_bak))
        {
            //新客户连接的时候， 开启新线程处理客户端请求
            //首先确定好传递给子线程的参数
            //-------------------------传递引用-------------------
            std::thread t_accept(acceptConn , std::ref(lfd),  std::ref(readfds),  std::ref(maxfd));
            t_accept.detach();
        }
        for(int i = lfd+1; i <= maxfd; i++)
        {
            if(FD_ISSET(i, &readfds_bak))
            {
                //创建子线程处理读取到的数据
                // FDInfo* info_ = new FDInfo();
                std::shared_ptr<FDInfo> info_ = std::make_shared<FDInfo>();
                info_->fd = i;
                info_->maxfd = &maxfd;
                info_->readfds = &readfds;  
                std::thread t_communication(communication, info_);
                t_communication.detach();                   
                
            }
        }
    }        
    
    close(lfd);
    
    return 0;
}